#include "const.h"
#include "ConfigMgr.h"
#include <grpcpp/grpcpp.h>
#include "message.pb.h"
#include "message.grpc.pb.h"

using grpc::Channel;
using grpc::Status;
using grpc::ClientContext;
using message::GetChatServerReq;
using message::GetChatServerRsp;
using message::StatusService;

class StatusConPool {
public:
    StatusConPool(size_t poolSize, std::string host, std::string port):poolSize_(poolSize),
    host_(host),port_(port),b_stop_(false){
        for (size_t i = 0; i < poolSize; ++i) {
            std::shared_ptr<Channel> channel = grpc::CreateChannel(host + ":" + port, grpc::InsecureChannelCredentials());;
            connections_.push(StatusService::NewStub(channel));
        }
    }
    ~StatusConPool(){
        std::lock_guard<std::mutex> lock(mutex_);
        Close();
        while (!connections_.empty()) {
            connections_.pop();
        }
    }
    std::unique_ptr<StatusService::Stub> getConnection() {
        std::unique_lock<std::mutex> lock(mutex_);
        cond_.wait(lock, [this] {
            if (b_stop_)
                return true;
            return !connections_.empty();
            });
        if (b_stop_) {
            return nullptr;
        }
        auto context = std::move(connections_.front());
        connections_.pop();
        return context;
    }
    void returnConnection(std::unique_ptr<StatusService::Stub> context) {
        std::lock_guard<mutex> lock(mutex_);
        if (b_stop_) {
            return;
        }
        connections_.push(std::move(context));
        cond_.notify_one();
    }
    void Close() {
        b_stop_ = true;
        cond_.notify_all();
    }

private:
    atomic<bool> b_stop_;
    std::queue<std::unique_ptr<StatusService::Stub>> connections_;
    std::string port_;
    std::string host_;
    size_t poolSize_;
    std::mutex mutex_;
    std::condition_variable  cond_;
};


class StatusGrpcClient:public Singleton<StatusGrpcClient> {
    friend class Singleton<StatusGrpcClient>;
public:
    GetChatServerRsp GetChatServer(int uid);
private:
    StatusGrpcClient();
    std::unique_ptr<StatusConPool> pool_;
};
